#ifndef UTILS_H
#define UTILS_H

#include "stdint.h"

//FE Range，单位bit
struct FERange{
    void *buffer;
    int64_t bit_offset; //-1表示同父节点offset(长子)或者紧接上一元素的偏移(次子)
    int64_t bit_len;    //-1表示所有子元素总长的跨度
};

int64_t remainFERange(FERange *range, int64_t bit_offset);
char *fetchFERange(FERange *range, int64_t bit_offset, int64_t bit_len, uint8_t *bit_first);
int subFERange(FERange *ori, FERange *sub, int64_t bit_offset, int64_t bit_len);

#define remainFERangeByte(range, offset) remainFERange(range, (offset) << 3) >> 3
#define fetchFERangeByte(range, offset, len) fetchFERange(range, (offset) << 3, (len) << 3, NULL)
#define subFERangeByte(ori, sub, offset, len) subFERange(ori, sub, (offset) << 3, (len) << 3)

//variable length code
enum FECode{
    FECodeGolomb,
    FECodeButt
};

uint8_t decodeFEDataFS(char *data, uint8_t bit_first, uint8_t bit_len, int32_t *value);
uint8_t decodeFEDataFU(char *data, uint8_t bit_first, uint8_t bit_len, uint32_t *value);
uint8_t decodeFEDataVS(char *data, uint8_t bit_first, uint8_t bit_max, FECode code, int32_t *value);
uint8_t decodeFEDataVU(char *data, uint8_t bit_first, uint8_t bit_max, FECode code, uint32_t *value);

//FE List
struct FEList {
    int get;
    int number;
    int reserve;
    int size;
    void *units;
};

void initFEList(FEList *list, int unit_size);
void *getNextFEUnit(FEList *list);
void putbackFEUnit(FEList *list);
void clearFEList(FEList *list);

/* Context:
 * 1. 所有文件format的top context都是null。
 * 2. 同一个format的所有视图的top contex格式必须一致。
 * 3. context提供者同时负责提供context的free函数, null free表示context无需释放，用于子节点复用父节点context情况。
 */
typedef void (*FreeContext)(void *context);

//format view
typedef int (*GetSubformat)(FERange range, void *context, FEList *subs);

struct FEFormat {
    size_t context_size;
    GetSubformat get;
};

struct FESubFormat {
    FERange range; //默认range。多range的情况，range列表包含在context中
    void *context;
    FreeContext free;
    char index[32];
};
int addSubFormat(FEList *subs, void *context, FreeContext free, const char *index);

//field view
struct FEField;
/* 域解析分为两步，综合得到域节点树和各节点显示字符串。建议如果某域的解释不依赖其他域，第一步只划分范围即可。
1. 分段
2. 格式化显示
*/
struct FEFieldNode {
    FEField *field;
    FERange range; //默认range。多range的情况，range列表包含在context中

    uint8_t depth; //相对子树深度。默认为0

    void *context;
    FreeContext free;

    int index1;
    int index2;
    int index3;

    enum {
        Raw,
        ToInt,
        ToUInt,
        ToFloat,
        ToText
    } translate_type;

    union {
        double d;
        int64_t i;
        uint64_t ui;
        struct {
            char *ptr;
            uint64_t len;
        }t;
    } translation;
};

/*  range : 解析限制区间
 *  return: 节点实际长度
*/
typedef int64_t (*DissectField)(FERange range, void *context, FEList *nodes);
typedef int (*DisplayField)(FEFieldNode *node, char *string, int len);

struct FEField {
    const char *name;
    size_t context_size;
    char   immediate; //节点是否应该被立即解析而不是延迟。主要应用于非子节点解析依赖本节点及子节点的值的情况
    DissectField dissect;
    DisplayField display;
};

FEFieldNode *allocFENode(FEList *nodes, FEField *field, FERange range);
int depthFENode(FEFieldNode *node, uint8_t depth);
int contextFENode(FEFieldNode *node, void *context, FreeContext free);
int indexFENode(FEFieldNode *node, int index1, int index2, int index3);
int translateFENodeFloat(FEFieldNode *node, double translation);
int translateFENodeUInt(FEFieldNode *node, uint64_t translation);
int translateFENodeInt(FEFieldNode *node, int64_t translation);
int translateFENodeText(FEFieldNode *node, char *translation, uint64_t translation_len);

// common display filter
int displayBool(FEFieldNode *node, char *string, int len);
int displayHex(FEFieldNode *node, char *string, int len);
int displayString(FEFieldNode *node, char *string, int len);

#endif // UTILS_H
